using System;
using System.Collections.Generic;
using System.Text;
using Toolbox.Picture;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Collections;

namespace Toolbox.ArrayRenderer
{

    public partial class ArrayPictureBox : ZoomPictureBox, IArrayRenderer
    {
        #region Delegate

        public delegate void Parser(RectangleF z, object o, params object[] parameters);

        private Parser rendering;

        public void SetRenderingFunction(Parser renderingFunction)
        {
            this.rendering = renderingFunction;
        }

        #endregion

        public ArrayPictureBox()
            : base()
        {
            this.InitializeComponent();
        }


        #region IArrayRenderer Members

        public bool IsRendering
        {
            get { return this.BackgroundRenderer.IsBusy; }
        }

        [ReadOnly(true)]
        public bool FullScan
        {
            get
            {
                return true;
            }
            set
            {
                throw new Exception("The method or operation is not implemented.");
            }
        }

        private ImageList icons;

        public ImageList ImageList
        {
            get { return this.icons; }
            set { this.icons = value; }
        }

        #endregion
      
        #region Object

        private int sizing;

        public void SetObject(IEnumerable a)
        {
            if (!this.BackgroundRenderer.IsBusy)
            {
                this.OnRendering();
                this.sizing = RenderingDimension(a);
                this.BackgroundRenderer.RunWorkerAsync(a);
            }
        }

        public void SetObject(IEnumerable a, int ratio)
        {
            if (!this.BackgroundRenderer.IsBusy)
            {
                this.OnRendering();
                this.sizing = ratio;
                this.BackgroundRenderer.RunWorkerAsync(a);
            }
        }

        public static int RenderingDimension(IEnumerable a)
        {
            int found = 1;
            int count = 0;

            foreach (object o in a)
            {
                count++;

                if (o is IEnumerable)
                {
                    int d = RenderingDimension(o as IEnumerable);

                    if (d > found)
                    {
                        found = d;
                    }
                }
            }

            return 5 * (int)Math.Sqrt(count) * found;
        }

        #endregion

        #region Render

        public event ProgressChangedEventHandler ProgressChangedEvent;

        public void ReportProgress(int percentProgress)
        {
            this.BackgroundRenderer.ReportProgress(percentProgress);
        }

        private void BackgroundRenderer_DoWork(object sender, DoWorkEventArgs e)
        {
            if (e.Argument is IEnumerable)
            {
                e.Result = new Bitmap(this.sizing, this.sizing);

                using (Graphics g = Graphics.FromImage(e.Result as Image))
                {
                    g.PageUnit = GraphicsUnit.Pixel;
                    this.rendering(RectangleF.FromLTRB(0, 0, this.sizing, this.sizing), e.Argument as IEnumerable, g);
                }
            }
        }

        private void BackgroundRenderer_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            if (this.ProgressChangedEvent != null)
            {
                this.ProgressChangedEvent(this, e);
            }
        }

        private void BackgroundRenderer_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.Image = e.Result as Image;
            this.OnRendered();
        }

        #endregion

        #region Events

        public event EventHandler Rendering;
        public event EventHandler Rendered;

        protected virtual void OnRendering()
        {
            this.UseWaitCursor = true;

            if (this.Rendering != null)
            {
                this.Rendering(this, new EventArgs());
            }
        }

        protected virtual void OnRendered()
        {
            this.UseWaitCursor = false;

            if (this.Rendered != null)
            {
                this.Rendered(this, new EventArgs());
            }
        }

        #endregion

        #region Static Helpers

        public static void ParseArray(Parser f, RectangleF z, Array m, params object[] parameters)
        {
            if (m.Rank > 1)
            {
                SizeF s = FindSizing(z.Size, m);

                for (int i = 0; i < m.GetLength(0); i++)
                {
                    for (int j = 0; j < m.GetLength(1); j++)
                    {
                        RectangleF r = FindZoning(i, j, s);
                        {
                            r.Offset(z.Location);

                            if (f != null)
                            {
                                f(r, m.GetValue(i, j), parameters);
                            }
                        }
                    }
                }
            }
        }

        private static SizeF FindSizing(SizeF s, Array m)
        {
            float w = s.Width / m.GetLength(0);
            float h = s.Height / m.GetLength(1);

            return new SizeF(w, h);
        }

        private static RectangleF FindZoning(int x, int y, SizeF s)
        {
            float xx = x * s.Width;
            float yy = y * s.Height;

            return new RectangleF(xx , yy , s.Width , s.Height);
        }

        #endregion


    }
}
